/* main.c */

#include <avr/io.h>

#include "delay.h"
#include "usart.h"

#define PIN_DATA  PB2 /* 14 blue */
#define PIN_CLOCK PB1 /* 11 orange */
#define PIN_LATCH PB0 /* 12 green  */

#define PIN_BUTTON PD7

#if 0
#define LATCH_LOW()   (PORTB &= ~(1 << PIN_LATCH))
#define LATCH_HIGH()  (PORTB |= (1 << PIN_LATCH))

#define CLOCK_LOW()   (PORTB &= ~(1 << PIN_CLOCK))
#define CLOCK_HIGH()  (PORTB |= (1 << PIN_CLOCK))

#define DATA_LOW()    (PORTB &= ~(1 << PIN_DATA))
#define DATA_HIGH()   (PORTB |= (1 << PIN_DATA))
#endif

void LATCH_LOW()
{
   (PORTB &= ~(1 << PIN_LATCH));
}

void LATCH_HIGH()
{
   (PORTB |= (1 << PIN_LATCH));
}

void CLOCK_LOW()
{
   (PORTB &= ~(1 << PIN_CLOCK));
}

void CLOCK_HIGH()
{
   (PORTB |= (1 << PIN_CLOCK));
}

void DATA_LOW()
{
   (PORTB &= ~(1 << PIN_DATA));
}

void DATA_HIGH()
{
   (PORTB |= (1 << PIN_DATA));
}


void setup()
{
   DDRB |= (1 << PIN_LATCH) | (1 << PIN_CLOCK) | (1 << PIN_DATA);
}

void foo(uint8_t c)
{
   LATCH_LOW();
   CLOCK_LOW();
   DATA_LOW();

   for (uint8_t i = 0; i <= 7; i++) {
      if (c & (1 << i)) {
         DATA_HIGH();
      } else {
         DATA_LOW();
      }
      
      CLOCK_HIGH();
      delay_us(2);
      CLOCK_LOW();
   }

   LATCH_HIGH();
   delay_us(8);
   LATCH_LOW();
}

void shift_out_8(uint8_t c)
{
   LATCH_LOW();
   {
      DATA_LOW();
      CLOCK_LOW();

      for (int8_t i = 7; i >= 0; i--) {
         CLOCK_LOW();
         if (c & (1 << i)) {
            DATA_HIGH();
         } else {
            DATA_LOW();
         }
         CLOCK_HIGH();
         DATA_LOW();
      }
      
      CLOCK_LOW();
   }
   LATCH_HIGH();
}

#define SHIFT_OUT_DIRECTION_L2R 0
#define SHIFT_OUT_DIRECTION_R2L 1

void shift_out_16(uint16_t v, uint16_t direction)
{
   if (direction == SHIFT_OUT_DIRECTION_L2R) {
      shift_out_8((uint8_t) (v >> 8));
      shift_out_8((uint8_t) (v & 0xff));
   } else {
      shift_out_8((uint8_t) (v & 0xff));
      shift_out_8((uint8_t) (v >> 8));
   }
}

int main(void)
{
   setup();
   usart_init(16000000 / 16 / 19200 - 1);
   
   shift_out_16(0b1110000000001111, SHIFT_OUT_DIRECTION_R2L);
   
   //shift_out_8(0x01);
   //shift_out_8(0x0f);

   while (1);

   while (1)
   {
      uint8_t load = usart_rx();
      
      uint16_t c = 0;
      for (uint8_t i = 0; i < load; i++) {
         c |= (1 << i);
      }
      
      shift_out_8((uint8_t) (c & 0xff));
      shift_out_8((uint8_t) (c >> 8));
      
      delay(1);
   }
   
   return 0;
}
